#include "main.h"
#include "ds1302.h"

// sbit DS1302_RST = P3^5;
// sbit DS1302_DAT = P3^4;
// sbit DS1302_CLK = P3^6;

sbit DS1302_RST = P2^2;
sbit DS1302_DAT = P2^1;
sbit DS1302_CLK = P2^0;

#define DS1302_DAT_READ()       DS1302_DAT
#define DS1302_DAT_SET(x)       { DS1302_DAT = x; _nop_(); }
#define DS1302_CLK_SET(x)       { DS1302_CLK = x; _nop_(); }
#define DS1302_RST_SET(x)       { DS1302_RST = x; _nop_(); }

/* 发送一个字节到DS1302通信总线上 */
void DS1302ByteWrite(unsigned char dat)
{
    unsigned char mask;
    
    for (mask=0x01; mask!=0; mask<<=1)  //低位在前，逐位移出
    {
        if ((mask&dat) != 0) //首先输出该位数据
        {
            DS1302_DAT_SET(1);
        }
        else {
            DS1302_DAT_SET(0);
        }
        DS1302_CLK_SET(1);       //然后拉高时钟
        DS1302_CLK_SET(0);       //再拉低时钟，完成一个位的操作
    }
}

/* 由DS1302通信总线上读取一个字节 */
unsigned char DS1302ByteRead()
{
    unsigned char mask;
    unsigned char dat = 0;
    
    for (mask=0x01; mask!=0; mask<<=1)  //低位在前，逐位读取
    {
        if (DS1302_DAT_READ() != 0)  //首先读取此时的IO引脚，并设置dat中的对应位
        {
            dat |= mask;
        }
        DS1302_CLK_SET(1);       //然后拉高时钟
        DS1302_CLK_SET(0);       //再拉低时钟，完成一个位的操作
    }
    return dat;              //最后返回读到的字节数据
}


/* 用单次写操作向某一寄存器写入一个字节，reg-寄存器地址，dat-待写入字节 */
void DS1302SingleWrite(unsigned char reg, unsigned char dat)
{
    DS1302_RST_SET(0);
    DS1302_CLK_SET(0);//先将SCLK置低电平。

    DS1302_RST_SET(1);                   //使能片选信号
    DS1302ByteWrite((reg<<1)|0x80);  //发送写寄存器指令
    DS1302ByteWrite(dat);            //写入字节数据
    DS1302_RST_SET(0);                   //除能片选信号
}

/* 用单次读操作从某一寄存器读取一个字节，reg-寄存器地址，返回值-读到的字节 */
unsigned char DS1302SingleRead(unsigned char reg)
{
    unsigned char dat;

    DS1302_RST_SET(0);
    DS1302_CLK_SET(0);//先将SCLK置低电平。

    DS1302_RST_SET(1);                   //使能片选信号
    DS1302ByteWrite((reg<<1)|0x81);  //发送读寄存器指令
    dat = DS1302ByteRead();          //读取字节数据
    DS1302_RST_SET(0);                   //除能片选信号

    //以下为DS1302复位的稳定时间,必须的。
    DS1302_CLK_SET(1);
    DS1302_DAT_SET(0);
    DS1302_DAT_SET(1);
    return dat;
}

/* 用突发模式连续写入8个寄存器数据，dat-待写入数据指针 */
void DS1302BurstWrite(unsigned char *dat)
{
    unsigned char i;
    
    DS1302_RST_SET(0);
    DS1302_CLK_SET(0);//先将SCLK置低电平。

    DS1302_RST_SET(1);                   //使能片选信号
    DS1302ByteWrite(0xBE);  //发送突发写寄存器指令
    for (i=0; i<8; i++)     //连续写入8字节数据
    {
        DS1302ByteWrite(dat[i]);
    }
    DS1302_RST_SET(0);                   //除能片选信号
}

/* 用突发模式连续读取8个寄存器的数据，dat-读取数据的接收指针 */
void DS1302BurstRead(unsigned char *dat)
{
    unsigned char i;

    DS1302_RST_SET(0);
    DS1302_CLK_SET(0);//先将SCLK置低电平。

    DS1302_RST_SET(1);                   //使能片选信号
    DS1302ByteWrite(0xBF);  //发送突发读寄存器指令
    for (i=0; i<8; i++)     //连续读取8个字节
    {
        dat[i] = DS1302ByteRead();
    }
    DS1302_RST_SET(0);                   //除能片选信号

    //以下为DS1302复位的稳定时间,必须的。
    DS1302_CLK_SET(1);
    DS1302_DAT_SET(0);
    DS1302_DAT_SET(1);
}

/* 获取实时时间，即读取DS1302当前时间并转换为时间结构体格式 */
void GetRealTime(struct sTime *time)
{
    unsigned char buf[8];
    DS1302BurstRead(buf);

    time->year = ((buf[6] >> 4) * 10) + (buf[6] & 0x0f) + 2000;
    time->mon  = ((buf[4] >> 4) * 10) + (buf[4] & 0x0f);
    time->day  = ((buf[3] >> 4) * 10) + (buf[3] & 0x0f);
    time->hour = ((buf[2] >> 4) * 10) + (buf[2] & 0x0f);
    time->min  = ((buf[1] >> 4) * 10) + (buf[1] & 0x0f);
    time->sec  = ((buf[0] >> 4) * 10) + (buf[0] & 0x0f);
    time->week = ((buf[5] >> 4) * 10) + (buf[5] & 0x0f);
}

/* 设定实时时间，时间结构体格式的设定时间转换为数组并写入DS1302 */
void SetRealTime(struct sTime *time)
{
    unsigned char buf[8];
    buf[7] = 0;
    buf[6] = ((time->year / 10) << 4) | (time->year % 10) ;
    buf[5] = ((time->week / 10) << 4) | (time->week % 10) ;
    buf[4] = ((time->mon  / 10) << 4) | (time->mon  % 10) ;
    buf[3] = ((time->day  / 10) << 4) | (time->day  % 10) ;
    buf[2] = ((time->hour / 10) << 4) | (time->hour % 10) ;
    buf[1] = ((time->min  / 10) << 4) | (time->min  % 10) ;
    buf[0] = ((time->sec  / 10) << 4) | (time->sec  % 10) ;

    DS1302SingleWrite(7, 0x00);  //撤销写保护以允许写入数据
    DS1302BurstWrite(buf);
    DS1302SingleWrite(7, 0x80);  //写保护以允许写入数据
}

/* DS1302初始化，如发生掉电则重新设置初始时间 */
void InitDS1302()
{
    unsigned char i;
    unsigned char code InitTime[8] = {  //2013年10月8日 星期二 12:30:00
        0x00, 0x30, 0x12, 0x08, 0x10, 0x02, 0x13, 0x00
    };

    DS1302_RST_SET(0); //初始化DS1302通信引脚
    DS1302_CLK_SET(0);

    i = DS1302SingleRead(0);  //读取秒寄存器

    if ((i & 0x80) != 0)      //由秒寄存器最高位CH的值判断DS1302是否已停止
    {
        DS1302SingleWrite(7, 0x00);  //撤销写保护以允许写入数据
        DS1302BurstWrite(InitTime);  //设置DS1302为默认的初始时间
        DS1302SingleWrite(7, 0x80);  //写保护以允许写入数据
    }
}
